package com.doraemon.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.doraemon.constant.MessageConstant;
import com.doraemon.constant.StatusConstant;
import com.doraemon.dto.SetmealDTO;
import com.doraemon.dto.SetmealPageQueryDTO;
import com.doraemon.entity.Dish;
import com.doraemon.entity.Setmeal;
import com.doraemon.entity.SetmealDish;
import com.doraemon.exception.DeletionNotAllowedException;
import com.doraemon.exception.SetmealEnableFailedException;
import com.doraemon.mapper.DishMapper;
import com.doraemon.mapper.SetmealDishMapper;
import com.doraemon.mapper.SetmealMapper;
import com.doraemon.result.PageResult;
import com.doraemon.service.SetmealService;
import com.doraemon.vo.DishItemVO;
import com.doraemon.vo.SetmealVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 套餐管理Service实现
 **/
@Service
public class SetmealServiceImpl implements SetmealService {

    @Autowired
    private SetmealMapper setmealMapper;
    @Autowired
    private SetmealDishMapper setmealDishMapper;
    @Autowired
    private DishMapper dishMapper;

    /***
     * 新增套餐，同时保存套餐与菜品关联关系
     * -由Spring事务管理-
     * ---
     * @param setmealDTO 套餐DTO类
     * @return: void
     */
    @Transactional
    @Override
    public void addSetmealWithDish(SetmealDTO setmealDTO) {

        // 1.创建套餐实体
        Setmeal setmeal = new Setmeal();

        // 2.调用工具类BeanUtils，将套餐DTO类拷贝到套餐实体
        BeanUtils.copyProperties(setmealDTO, setmeal);

        // 3.调用套餐Mapper层，新增套餐
        setmealMapper.insert(setmeal);

        // 4.获取套餐DTO类包含的套餐菜品实体集合
        List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();

        // 5.调用套餐菜品Mapper层，将套餐菜品数据插入到套餐菜品表
        for (SetmealDish setmealDish : setmealDishes) {
            // 6.主键回显，将插入之后生成的 套餐id 赋值给 套餐菜品实体对应的套餐id属性
            setmealDish.setSetmealId(setmeal.getId());
            setmealDishMapper.insert(setmealDish);
        }
    }

    /***
     * 分页查询套餐
     * ---
     * @param setmealPageQueryDTO 套餐分页DTO类
     * @return: com.doraemon.result.PageResult 分页结果集对象
     */
    @Override
    public PageResult pageQuery(SetmealPageQueryDTO setmealPageQueryDTO) {

        // 1.使用PageHelper插件
        // 传递页码和每页展示的记录数，自动对SQL语句进行改写
        PageHelper.startPage(setmealPageQueryDTO.getPage(), setmealPageQueryDTO.getPageSize());

        // 2.执行套餐信息的查询获取Page对象
        Page<SetmealVO> page = setmealMapper.pageQuery(setmealPageQueryDTO);

        // 3.调用Page类型的方法来获取总记录数和结果集，并封装成PageResult返回
        return new PageResult(page.getTotal(), page.getResult());
    }

    /***
     * 批量删除套餐
     * -由Spring事务管理-
     * ---
     * @param ids 套餐id集合
     * @return: void
     */
    @Transactional
    @Override
    public void deleteBatch(List<Long> ids) {

        // 1.判断套餐是否能被删除（是否为起售状态）
        for (Long id : ids) {
            // 调用套餐Mapper层，根据套餐id获取套餐实体
            Setmeal setmeal = setmealDishMapper.getById(id);
            if (setmeal.getStatus() == StatusConstant.ENABLE) { // 如果菜品为起售状态，抛出自定义异常和自定义异常信息
                throw new DeletionNotAllowedException(MessageConstant.SETMEAL_ON_SALE);
            }
        }

        for (Long id : ids) {
            // 2.调用套餐Mapper层，删除套餐
            setmealMapper.deleteById(id);

            // 3.调用套餐菜品Mapper层，删除套餐与菜品关联信息
            setmealDishMapper.deleteBySetmealId(id);
        }
    }

    /***
     * 修改套餐，同时修改套餐与菜品关联关系
     * ---
     * @param setmealDTO 套餐DTO类
     * @return: void
     */
    @Override
    public void updateWithDish(SetmealDTO setmealDTO) {

        // 1.创建套餐实体
        Setmeal setmeal = new Setmeal();

        // 2.调用工具类BeanUtils，将套餐DTO类拷贝到套餐实体
        BeanUtils.copyProperties(setmealDTO, setmeal);

        // 3.调用套餐Mapper层，修改套餐
        setmealMapper.update(setmeal);

        // 4.删除原有套餐与菜品关联关系
        setmealDishMapper.deleteBySetmealId(setmeal.getId());

        // 5.重新插入套餐与菜品关联关系
        // 获取套餐DTO类中的套餐菜品集合
        List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();
        // 套餐菜品集合进行非空非null判断
        if (setmealDishes != null && setmealDishes.size() > 0) {
            for (SetmealDish setmealDish : setmealDishes) {
                setmealDish.setSetmealId(setmeal.getId()); // 对每个套餐菜品插入对应的套餐id
                // 调用套餐菜品Mapper层，插入数据
                setmealDishMapper.insert(setmealDish);
            }
        }
    }

    /***
     * 根据id查询套餐和对应的菜品关系
     * ---
     * @param id 套餐id
     * @return: com.doraemon.result.Result<com.doraemon.dto.SetmealDTO>  套餐VO类
     */
    @Override
    public SetmealVO getByIdWithDish(Long id) {

        // 1.调用套餐Mapper层，根据套餐id获取套餐实体
        Setmeal setmeal = setmealMapper.getById(id);

        // 2.调用套餐菜品Mapper层，根据套餐id获取套餐菜品实体集合
        List<SetmealDish> setmealDishes = setmealDishMapper.getListBySetmealId(id);

        // 3.将查询到的数据封装到SetmealDTO类
        SetmealVO setmealVO = new SetmealVO();
        BeanUtils.copyProperties(setmeal, setmealVO); // 调用工具类BeanUtils，将套餐实体拷贝到套餐VO类
        setmealVO.setSetmealDishes(setmealDishes); // 将套餐菜品数据赋值VO类

        return setmealVO;
    }

    /***
     * 修改套餐售卖状态
     * ---
     * @param status 套餐售卖状态 0 停售 1 起售
     * @param id 套餐id
     * @return: com.doraemon.result.Result<java.lang.String>
     */
    @Override
    public void updateStatus(Integer status, Long id) {

        // 1.如果是修改为起售状态
        if (status == StatusConstant.ENABLE) {

            // 2.判断套餐内是否有停售菜品
            List<Dish> dishes = dishMapper.getListBySetmealId(id);

            // 3.如果套餐内包含停售商品，抛出自定义异常和自定义异常信息
            for (Dish dish : dishes) {
                if (dish.getStatus() == StatusConstant.DISABLE) {
                    throw new SetmealEnableFailedException(MessageConstant.SETMEAL_ENABLE_FAILED);
                }
            }
        }

        // 4.根据status，id属性创建套餐实体
        Setmeal setmeal = new Setmeal();
        setmeal.setStatus(status);
        setmeal.setId(id);

        // 5.调用套餐Mapper层，更新套餐
        setmealMapper.update(setmeal);
    }

    /***
     * 通过套餐实体查询起售状态的套餐实体集合
     * ---
     * @param setmeal 套餐实体
     * @return: java.util.List<com.doraemon.entity.Setmeal>
     */
    @Override
    public List<Setmeal> getListBySetmeal(Setmeal setmeal) {

        // 调用套餐Mapper层，获取起售的套餐集合
        List<Setmeal> setmeals = setmealMapper.list(setmeal);

        return setmeals;
    }

    /***
     * 根据套餐id获取包含的菜品列表VO类集合
     * ---
     * @param id 套餐id
     * @return: java.util.List<com.doraemon.vo.DishItemVO> 菜品列表VO类集合
     */
    @Override
    public List<DishItemVO> getDishItemVOListById(Long id) {

        // 调用套餐Mapper层，获取包含的菜品列表VO类集合
        List<DishItemVO> dishItemVOS = setmealMapper.getDishItemVOListById(id);

        return dishItemVOS;
    }

}
